package com.scpii.universal.hibernate.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import com.scpii.universal.hibernate.dao.BaseDao;

/**
 * universalWeb
 * 
 * @author liuhj 2012-7-5上午11:08:34
 * @param <T>
 * @param <PK>
 */
@Repository
public class BaseDaoImpl<T, PK extends Serializable> extends
		HibernateDaoSupport implements BaseDao<T, PK> {

	private Class<T> entityClass;

	@Resource(name = "sessionFactory")
	public void setSuperSessionFactory(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}

	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		this.entityClass = null;
		Class c = getClass();
		Type type = c.getGenericSuperclass();
		// 动态获取实体
		if (type instanceof ParameterizedType) {
			Type[] parameterizedType = ((ParameterizedType) type)
					.getActualTypeArguments();
			this.entityClass = (Class<T>) parameterizedType[0];
		}
	}

	@Override
	public void delete(T obj) {
		getHibernateTemplate().delete(obj);
	}

	@Override
	public void delete(PK id) {
		T obj = load(id);
		getHibernateTemplate().delete(obj);
	}

	@Override
	public T get(PK id) {
		return getHibernateTemplate().get(entityClass, id);
	}

	@Override
	@SuppressWarnings("unchecked")
	public T get(String propertyName, Object value) {
		String hql = "from " + entityClass.getName()
				+ " as entity where entity." + propertyName + " = ?";
		return (T) getHibernateTemplate().getSessionFactory()
				.getCurrentSession().createQuery(hql).setParameter(0, value)
				.uniqueResult();
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<T> getAll() {
		String hql = "from " + entityClass.getName();
		return getHibernateTemplate().getSessionFactory().getCurrentSession()
				.createQuery(hql).list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<T> getList(String propertyName, Object value) {
		String hql = "from " + entityClass.getName()
				+ " as entity where entity." + propertyName + " = ?";
		return getHibernateTemplate().getSessionFactory().getCurrentSession()
				.createQuery(hql).setParameter(0, value).list();
	}

	@Override
	public Long getTotalCount() {
		String hql = "select count(*) from " + entityClass.getName();
		return (Long) getHibernateTemplate().getSessionFactory()
				.getCurrentSession().createQuery(hql).uniqueResult();
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<T> hqlGetList(final String hql,
			final Map<String, Object> argsMap) {
		/*
		 * Session session =
		 * this.getHibernateTemplate().getSessionFactory().getCurrentSession();
		 * if (namedHqlQuery!=null && namedHqlQuery.trim().length()>0) { Query
		 * query = session.getNamedQuery(namedHqlQuery); if (argsMap!=null) {
		 * Set set = argsMap.entrySet(); Iterator iterator = set.iterator();
		 * while(iterator.hasNext()){ Map.Entry<String ,Object> entry =
		 * (Entry<String, Object>) iterator.next();
		 * query.setParameter(entry.getKey(), entry.getValue()); } } List<T>
		 * list = query.list(); return list; } return null;
		 */
		List<T> lstResult = null;
		lstResult = getHibernateTemplate().executeFind(
				new HibernateCallback<T>() {
					@Override
					public T doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						if (argsMap != null) {
							Set<String> keySet = argsMap.keySet();
							for (String string : keySet) {
								Object obj = argsMap.get(string);
								if (obj instanceof Collection<?>) {
									query.setParameterList(string,
											(Collection<?>) obj);
								} else if (obj instanceof Object[]) {
									query.setParameterList(string,
											(Object[]) obj);
								} else {
									query.setParameter(string, obj);
								}
							}
						}
						return (T) query.list();
					}

				});
		return lstResult;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Long hqlGetNums(String namedHqlQuery, Map<String, Object> argsMap) {
		Session session = this.getHibernateTemplate().getSessionFactory()
				.getCurrentSession();
		if (namedHqlQuery != null && namedHqlQuery.trim().length() > 0) {
			Query query = session.getNamedQuery(namedHqlQuery);
			// 设置对应的参数值
			if (argsMap != null) {
				Set set = argsMap.entrySet();
				Iterator iterator = set.iterator();
				while (iterator.hasNext()) {
					Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
							.next();
					query.setParameter(entry.getKey(), entry.getValue());
				}
			}
			List list = query.list();
			if (list != null && list.size() == 0) {
				return (Long) list.get(0);
			}
		}
		return new Long(0);
	}

	@Override
	@SuppressWarnings("unchecked")
	public void hqlUpdate(String namedHqlQuery, Map<String, Object> argsMap) {
		Session session = this.getHibernateTemplate().getSessionFactory()
				.getCurrentSession();
		if (namedHqlQuery != null && namedHqlQuery.trim().length() > 0) {
			Query query = session.getNamedQuery(namedHqlQuery);
			// 设置对应的参数值
			if (argsMap != null) {
				Set set = argsMap.entrySet();
				Iterator iterator = set.iterator();
				while (iterator.hasNext()) {
					Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
							.next();
					query.setParameter(entry.getKey(), entry.getValue());
				}
			}
			// 执行操作
			query.executeUpdate();
		}
	}

	@Override
	public T load(PK id) {
		return getHibernateTemplate().load(entityClass, id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public PK save(T obj) {
		return (PK) getHibernateTemplate().save(obj);
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<T> sqlGetList(String sqls, Map<String, Object> argsMap) {
		if (sqls != null & sqls.trim().length() > 0) {
			Session session = this.getHibernateTemplate().getSessionFactory()
					.getCurrentSession();
			Query query = session.createSQLQuery(sqls).addEntity(entityClass);
			// 设置对应的参数值
			if (argsMap != null) {
				Set set = argsMap.entrySet();
				Iterator iterator = set.iterator();
				while (iterator.hasNext()) {
					Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
							.next();
					query.setParameter(entry.getKey(), entry.getValue());
				}
			}
			List list = query.list();
			return list;
		}
		return null;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Long sqlGetNum(String sqls, Map<String, Object> argsMap) {
		if (sqls != null && sqls.trim().length() > 0) {
			Session session = this.getHibernateTemplate().getSessionFactory()
					.getCurrentSession();
			Query query = session.createSQLQuery(sqls).addEntity(entityClass);
			// 设置对应的参数值
			if (argsMap != null) {
				Set set = argsMap.entrySet();
				Iterator iterator = set.iterator();
				while (iterator.hasNext()) {
					Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
							.next();
					query.setParameter(entry.getKey(), entry.getValue());
				}
			}
			List list = query.list();
			if (list != null && list.size() == 1) {
				return (Long) list.get(0);
			}
		}
		return new Long(0);
	}

	/**
	 * 根据条件查询结果的记录条数
	 */
	@SuppressWarnings("unchecked")
	public Integer getRecordNum(String sqlName, Map<String, Object> argsMap) {
		if (sqlName != null && !sqlName.trim().equals("")) {
			Session session = super.getHibernateTemplate().getSessionFactory()
					.getCurrentSession();
			Query query = session.createSQLQuery(sqlName);
			if (argsMap != null) {
				Set set = argsMap.entrySet();
				Iterator iterator = set.iterator();
				while (iterator.hasNext()) {
					Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
							.next();
					query.setParameter(entry.getKey(), entry.getValue());
				}
				List list = query.list();
				if (list != null && list.size() == 1) {
					BigDecimal result = (BigDecimal) list.get(0);
					return Integer.parseInt(result + "");
				}
			}
		}
		return 0;
	}

	@Override
	@SuppressWarnings("unchecked")
	public void sqlUpdate(String sqls, Map<String, Object> argsMap) {
		if (sqls != null && sqls.trim().length() > 0) {
			Session session = this.getHibernateTemplate().getSessionFactory()
					.getCurrentSession();
			Query query = session.createSQLQuery(sqls).addEntity(entityClass);
			// 设置参数值
			if (argsMap != null) {
				Set set = argsMap.entrySet();
				Iterator iterator = set.iterator();
				while (iterator.hasNext()) {
					Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
							.next();
					query.setParameter(entry.getKey(), entry.getValue());
				}
			}
			query.executeUpdate();
		}
	}

	@Override
	public void update(T obj) {
		getHibernateTemplate().update(obj);
	}

	@Override
	public void hqlOperation(final String hql, final Map<String, Object> argsMap) {
		getHibernateTemplate().executeFind(new HibernateCallback<T>() {

			@Override
			public T doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createQuery(hql);
				if (argsMap != null) {
					Set<String> keySet = argsMap.keySet();
					for (String string : keySet) {
						Object obj = argsMap.get(string);
						if (obj instanceof Collection<?>) {
							query.setParameterList(string, (Collection<?>) obj);
						} else if (obj instanceof Object[]) {
							query.setParameterList(string, (Object[]) obj);
						} else {
							query.setParameter(string, obj);
						}
					}
				}
				query.executeUpdate();
				return null;
			}
		});
	}

	/**
	 * @param : pageNo-第几页(若为0，则查询全部)
	 * @param : pageSize-一页显示多少条数据(若为0，则查询全部)
	 * @param : hql-hql语句
	 * @param : map-封装hql语句中的参数
	 * @return : List查询结果以list集合形式存储
	 * @throws : Exception
	 * @author : wangjun create time : 2011-5-28-上午10:21:10 Description ：
	 *         Hql语句分页查询数据集合 example: String
	 *         hql="from Location loc where loc.name=:name and loc.id=:id"; Map
	 *         map=new HashMap(); map.put("name","example"); map.put("id",1);
	 *         findByHql(hql,1,10,map);
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByHql(final String hql, final int pageNo,
			final int pageSize, final Map<String, Object> map) {
		List<T> lstResult = null;

		lstResult = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (map != null) {
					Iterator<String> it = map.keySet().iterator();
					while (it.hasNext()) {
						Object key = it.next();
						query.setParameter(key.toString(), map.get(key));
					}
				}
				if (pageNo != 0 && pageSize != 0) {
					query.setFirstResult((pageNo - 1) * pageSize);
					query.setMaxResults(pageSize);
				}
				return query.list();
			}
		});

		return lstResult;
	}

	@Override
	public String generateHqlByProperties(String[] properties) {
		StringBuffer hql = new StringBuffer();
		int len = 0;
		if (properties != null) {
			len = properties.length;
		}
		if (properties == null || len <= 0) {
			hql.append("from " + entityClass.getName() + " as entity ");
			return hql.toString();
		}
		hql.append("select new " + entityClass.getName() + "(");
		for (int i = 0; i < properties.length; i++) {
			hql.append("entity." + properties[i] + ",");
		}
		hql = hql.deleteCharAt(hql.lastIndexOf(",")).append(") from ")
				.append(entityClass.getName() + " as entity ");
		return hql.toString();
	}

	/**
	 * 调用Oracle的存储过程或者函数
	 * 
	 * @return
	 * @author 甘建新 2012-9-21下午02:20:42
	 */
	@Override
	public List executeFunction(String procOrFuncSql,
			Map<String, Object> argsMap) {
		Session session = getHibernateTemplate().getSessionFactory()
				.openSession();
		SQLQuery sqlQuery = session.createSQLQuery(procOrFuncSql);
		if (argsMap != null) {
			Set set = argsMap.entrySet();
			Iterator iterator = set.iterator();
			while (iterator.hasNext()) {
				Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
						.next();
				sqlQuery.setParameter(entry.getKey(), entry.getValue());
			}
		}
		List list = sqlQuery.list();
		return list;
	}

	@Override
	public void flushAndClear() {
		getHibernateTemplate().getSessionFactory().getCurrentSession().flush();
		getHibernateTemplate().getSessionFactory().getCurrentSession().clear();
	}

	@SuppressWarnings("unchecked")
	public List<T> findByHql(final String hql, final int pageNo,
			final int pageSize, final Map<String, Object> map,
			final List<Integer> ids) {
		List<T> lstResult = null;

		lstResult = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				System.out.println(hql);
				Query query = session.createQuery(hql);
				if (map != null) {
					Iterator<String> it = map.keySet().iterator();
					while (it.hasNext()) {
						Object key = it.next();

						query.setParameter(key.toString(), map.get(key));

					}

				}
				if (ids != null) {
					query.setParameterList("ids", ids);
				}
				if (pageNo != 0 && pageSize != 0) {
					query.setFirstResult((pageNo - 1) * pageSize);
					query.setMaxResults(pageSize);
				}
				return query.list();
			}
		});
		return lstResult;
	}

	@SuppressWarnings("unchecked")
	public List<Long> findByHqlCount(final String hql, final int pageNo,
			final int pageSize, final Map<String, Object> map,
			final List<Integer> ids) {
		List<Long> lstResult = null;

		lstResult = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (map != null) {
					Iterator<String> it = map.keySet().iterator();
					while (it.hasNext()) {
						Object key = it.next();
						query.setParameter(key.toString(), map.get(key));
					}

				}
				if (ids != null) {
					query.setParameterList("ids", ids);
				}
				if (pageNo != 0 && pageSize != 0) {
					query.setFirstResult((pageNo - 1) * pageSize);
					query.setMaxResults(pageSize);
				}
				return query.list();
			}
		});
		return lstResult;
	}

	public List getObjectByHql(String queryName, Map<String, Object> argsMap)
			throws Exception {
		SessionFactory sessionFactory = super.getHibernateTemplate()
				.getSessionFactory();
		Session session = sessionFactory.getCurrentSession();
		Query query = session.getNamedQuery(queryName);
		if (argsMap != null) {
			Set set = argsMap.entrySet();
			Iterator iterator = set.iterator();
			while (iterator.hasNext()) {
				Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
						.next();
				query.setParameter(entry.getKey(), entry.getValue());
			}
		}
		List list = query.list();
		return list;
	}

	public void updateByHql(String namedHql, Map<String, Object> argsMap)
			throws Exception {
		Session session = getHibernateTemplate().getSessionFactory()
				.getCurrentSession();
		if (namedHql != null && !namedHql.equals("")) {
			Query query = session.getNamedQuery(namedHql);
			Set set = argsMap.entrySet();
			Iterator iterator = set.iterator();
			while (iterator.hasNext()) {
				Map.Entry<String, Object> entry = (Entry<String, Object>) iterator
						.next();
				query.setParameter(entry.getKey(), entry.getValue());
			}
			int i = query.executeUpdate();
		} else {
			return;
		}
	}
}
